estimateCostOfDebt<-function(inData=yieldData,minConstraint=NULL ,
                             maxConstraint=NULL,sigmaKernel=sigmaKernel) {
  #inData=yieldData$yields; minConstraint<-maxConstraint<-NULL
 
  # can specify more: targetTenors etc.
  
  # functions checking inData
  dNames<-names(inData)
  dMatch<-match(dNames,c("tenor","yield","faceValue"))
  missingName<-is.na(dMatch)
  if(sum(missingName)>0) {
    stop("You are missing one of: \"tenor\"; \"yield\"; \"faceValue\"\n")
  }
  missingNumeric<-!apply(inData,2,is.numeric)
  if(sum(missingNumeric)>0) {
    stop("Your data are not all numeric\n")
  }
  
  # other logical checks ...

  # set constraints if NULL
  if(is.null(minConstraint)) {
    minConstraint<-c( 0,-15,-30,-30, 0,2.5,0)
    maxConstraint<-c(15, 30, 30, 30, 2.5, 5.5,30)
    minConstraintNS<-minConstraint[c(1:3,5)]
    maxConstraintNS<-maxConstraint[c(1:3,5)]
  }else{
    if(length(minConstraint)!=6) {
      stop("You have not specified a minConstraint of six parameters\n
corresponding to {B0;B1;B2;B3;Lambda1;Lambda2} of the\n
NSS model\n")
    }
    minConstraintNS<-minConstraint[c(1:3,5)]
    maxConstraintNS<-maxConstraint[c(1:3,5)]
  }
 
  # define metaparameters of the solution
  algo <- list(nP = 100L,
               nG = 500L,
               F = 0.50,
               CR = 0.99,
               min = minConstraint,
               max = maxConstraint,
               pen = penalty,
               repair = NULL,
               loopOF = TRUE,
               loopPen = FALSE,
               loopRepair = TRUE,
               printBar = FALSE,
               printDetail = FALSE)
  
  # define data object with constraints
  inData$weights<-inData$faceValue/sum(inData$faceValue)
  
  dataObject <- list(yM = inData$yield,
                  tm = inData$tenor,
                  model = NSS,
                  min = minConstraint,
                  max = maxConstraint,
                  ww = 1,
                  weighting = inData$weights)

  # calculate Nadaraya-Watson (NW) kernel estimate weighted by face value
  costOfDebtKernel<-sm::sm.regression(inData$tenor,inData$yield ,h=sigmaKernel,
                    weights=inData$faceValue,display="none",
                    eval.points=c(3,5,7,10))$estimate
  
  # calculate RBA version of NW kernel used by Authority
  # do as separate function when refactoring
  tauGauss_10<- dnorm(inData$tenor,mean=10,sd=sigmaKernel)
  tauWeight_10<-tauGauss_10*inData$faceValue
  tauWeight_10<-tauWeight_10/sum(tauWeight_10)
  
  tauGauss_7<- dnorm(inData$tenor,mean=7,sd=sigmaKernel)
  tauWeight_7<-tauGauss_7*inData$faceValue#/sum(yieldData$faceValue)
  tauWeight_7<-tauWeight_7/sum(tauWeight_7)
  
  tauGauss_5<- dnorm(inData$tenor,mean=5,sd=sigmaKernel)
  tauWeight_5<-tauGauss_5*inData$faceValue
  tauWeight_5<-tauWeight_5/sum(tauWeight_5)
  
  tauGauss_3<- dnorm(inData$tenor,mean=3,sd=sigmaKernel)
  tauWeight_3<-tauGauss_3*inData$faceValue#/sum(yieldData$faceValue)
  tauWeight_3<-tauWeight_3/sum(tauWeight_3)
  
  
  targetTenorYield<- c(sum(tauWeight_3*inData$yield),
                       sum(tauWeight_5*inData$yield),
                       sum(tauWeight_7*inData$yield),
                       sum(tauWeight_10*inData$yield))
  
  tauWeight_3<-tauWeight_3/sum(tauWeight_3)*inData$tenor
  tauWeight_5<-tauWeight_5/sum(tauWeight_5)*inData$tenor
  tauWeight_7<-tauWeight_7/sum(tauWeight_7)*inData$tenor
  tauWeight_10<-tauWeight_10/sum(tauWeight_10)*inData$tenor
  
  adjTenor<- c(sum(tauWeight_3),sum(tauWeight_5),
               sum(tauWeight_7),sum(tauWeight_10))
 
  
  # calculate NSS estimate
  solNSS <- NMOF::DEopt(OF = OF, algo = algo, data = dataObject)
  
  costOfDebtNSS<-sapply(c(3,5,7,10),function(x) NMOF::NSS(solNSS$xbest,x))
  
  # dataObject$model <- NS
  inDataOrder<-order(inData$tenor)
  
  # solNS <- NMOF::DEopt(OF = OF, algo = algo, data = dataObject)
  solNS<-YieldCurve::Nelson.Siegel( inData$yield[inDataOrder], inData$tenor[inDataOrder] )
  solNS[4]<-1/solNS[4]
  solNS<-as.numeric(solNS)
  # sum((yieldData$yield - NS(test,yieldData$tenor))^2)
  # 
  costOfDebtNS<-sapply(c(3,5,7,10),function(x) NMOF::NS(solNS,x))
  OFvalueNS<-sum((inData$yield - NMOF::NS(solNS,inData$tenor))^2)
  # return cost of debt estimates
  solutions<-cbind(costOfDebtKernel,costOfDebtNS,costOfDebtNSS)
  colnames(solutions) <-c("kernel","NS","NSS")
  objective<-c(NS=OFvalueNS,NSS=solNSS$OFvalue)
  list(solutions=solutions,objective=objective,
              NSparameters=solNS,NSSparameters=solNSS$xbest,
       kernelRBA=cbind(adjustedTenor=adjTenor,yield=targetTenorYield) )
  # rm(inData,missingNumeric,missingName,objective,solutions,OFvalueNS,
  # costOfDebtKernel,costOfDebtNS,costOfDebtNSS,solNS,solNSS,dataObject,
  # algo,minConstraint,maxConstraint,dNames,dMatch)
}
#test<-estimateCostOfDebt()

### penalty function for DEOpt
penalty <- function(mP, data) {
  minV <- data$min
  maxV <- data$max
  ww <- data$ww
  
  ## if larger than maxV, element in A is positiv
  A <- mP - as.vector(maxV)
  A <- A + abs(A)
  
  ## if smaller than minV, element in B is positiv
  B <- as.vector(minV) - mP
  B <- B + abs(B)
  ## beta 1 + beta2 > 0
  C <- ww*((mP[1L, ] + mP[2L, ]) - abs(mP[1L, ] + mP[2L, ]))
  A <- ww * colSums(A + B) - C
  A
}

# Objective function for DEOpt
OF <- function(param,data) {
  y <- data$model(param,data$tm)
  aux <- (y - data$yM)^2
  res <- sum(aux)
  # aux <- y - data$yM
  # res <- max(abs(aux))
  
  ## compute the penalty
  aux <- y - abs(y) ## aux == zero for nonnegative y
  aux <- -sum(aux) * data$ww
  res <- res + aux
  if (is.na(res)) {
    res <- 1e10
  }else{
    #res<-sum(res*data$weighting)
    res<-sum(res)
    
      }
  res
}

# measure support: kernel density centred on target tenor
measureSupport<-function(inData=yieldData$tenor,h=sigmaKernel,targetTenor=10) {
  sum(dnorm(inData,mean=targetTenor,sd=h))
}
#measureSupport()

# function extracts data from excel spreadsheet that has downloaded Bloomberg bond yield data
extractYield<-function() {
  fChoose<-file.choose()
  #fChoose<-"name of excel file"
  inputPar<-read_excel(fChoose,sheet="Inputs",range="A3:B10",col_types = "text")
  
  # note, origin is "1904-01-01" for Excel on Mac
  determinationDate<-as.Date(as.numeric(inputPar[1,2]),origin=as.Date("1899-12-30"))
  
  nTradingDays<-as.numeric(inputPar[3,2])
  
  targetTenor<-as.numeric(inputPar[4,2])
  
  tradingPeriod<-read_excel(fChoose,sheet="Allowed trading days")
  tradingPeriod<-tradingPeriod[which(!is.na(tradingPeriod$Date)),]
  
  if(nrow(tradingPeriod)!=nTradingDays){
    stop(cat("The number of trading dates on sheet \"Allowed trading days\" does not 
             equal the number of trading days set in cell B5 of sheet \"Inputs\"\n"))
  }
  
  bondAttributes<-read_excel(fChoose,sheet="Inputs",skip=13)
  bondAttributes<-bondAttributes[which(!is.na(bondAttributes$ISIN)),]
  
  yieldMatrix<-matrix(NA,nrow=nrow(bondAttributes),ncol=nTradingDays)
  
  for(i in 1:nTradingDays) {
    yieldSheet<-read_excel(fChoose,sheet=i+3,skip=2)
    yieldSheet<-yieldSheet[which(!is.na(yieldSheet[,"PX BID"])),]
    yieldMatrix[,i]<-as.numeric(unlist(yieldSheet[,"Australian dollar equivalent yield"]))
    # can put other catches in here for identifying when
    #  data download is not complete ...
  }
  
  averageBondYield<-apply(yieldMatrix,1,mean,na.rm=TRUE)
  
  # IRS - annualised
  IRS<-mean(tradingPeriod$'10 Year IRS Rate')
  annualisedIRS<-((1+IRS/200)^2-1)*100
  
  list(yields=data.frame(tenor=bondAttributes$`Residual Maturity`,
                         yield=averageBondYield,
                         faceValue=bondAttributes$'Bond Face Value (AUD)'),
       determinationDate=determinationDate,
       creditRating=inputPar[2,2],
       nTradingDays=nTradingDays,       
       targetTenor=targetTenor,
       gkSigma = as.numeric(inputPar[7,2]),
       IRS=annualisedIRS,
       yieldMatrix=yieldMatrix,
       tradingPeriod=tradingPeriod,
       bonds=bondAttributes$`with \" Corp\"`,
       chosenFile=fChoose)
}

annualiseCOD<- function(inDebt=costDebt){
  ((1+inDebt/200)^2-1)*100
} 

calcKernel10yrExtapolation<-function(effectiveValues) {
  effectiveValues[3,2]+(effectiveValues[4,2]-effectiveValues[3,2])/
    (effectiveValues[4,1]-effectiveValues[3,1])*(10-effectiveValues[3,1])
}
